/**
 * SPDX-FileCopyrightText: 2023-2025 Sangfor Technologies Inc.
 * SPDX-License-Identifier: Mulan PSL v2
 */
/**
 * Created by ued on 2016/10/31.
 * 统一封装ajax请求
 */

import Vue from 'vue';
import VueResource from 'vue-resource';

// import store from 'src/vuex/store';
import logger from './logger';

// import { getStorage } from './local_storage';
import {
    isString
} from './typeof';

let inited = false;
const NO_AUTHORIZATION = 302; // 后续和后端确认统一请求错误的返回状态码
// const NO_LICENSE = 402; // 授权失败的状态码
const ERROR_TOKEN = 1001;       // 非法token的错误状态码 同后台 zxx 协商的
const SUCCESS_CODE = 200;
 /* eslint-disable */
const OVER_TIME = 60 * 1000;

import store from 'src/vuex/store';
let userID = store.state.userId;


/**
 * 初始化 vue-resource 一些统一的配置
 */

let requestCache = new Map();

export function init () {
    if (inited) {
        return;
    }
    inited = true;

    Vue.use(VueResource);
    Vue.http.options.emulateJSON = true;

    // 所有请求自动加上/bbc前缀，业务代码里请求有两种方式：
    // 1、this.$http.get('/test/url') 这种方式相对于整个对路径，不会自动加上root前缀
    // 2、this.$http.get('test/url') 会自动加上root前缀，即 /bbc/test/url
    Vue.http.options.root = '.';

    // 统一加上csrf头部信息
    // Vue.http.headers.common[CSRF_TOKEN] = getCSRF();
    Vue.http.headers.common['Kubeflow-Userid'] = 'kubeflow-user-example-com@sangfor.com';
    Vue.http.headers.common['username'] = userID;

    // 设置 request 中断处理
    Vue.http.interceptors.push((request, next) => {
        let {abort, ajaxIdentity} = request;

        if (abort) {
            if (!ajaxIdentity) {
                ajaxIdentity = `${request.url}_${request.method}`;
            }

            if (requestCache.has(ajaxIdentity)) {
                requestCache.get(ajaxIdentity).abort();
                requestCache.delete(ajaxIdentity);
            }

            requestCache.set(ajaxIdentity, request);
        }

        next(() => {
            if (abort) {
                requestCache.delete(ajaxIdentity);
            }
        });
    });

    /* eslint-disable */
    // 设置 timeout 超时时间后，当其超时 cancel 了，不会返回任何东西，在这里改写成 _timeout
    Vue.http.interceptors.push((request, next) => {
        let timeout;

        if (request._timeout) {
            timeout = window.setTimeout(() => {
                request.abort();
                next(request.respondWith(request.body, {
                    status: 408,
                    jsonData: {
                        success: false,
                        message: _('请求超时')
                    }
                }));
            }, request._timeout);
        }

        next(() => {
            clearTimeout(timeout);
        });
    });
    /* eslint-enable */

    // hook，数据自动转成json后再交给业务处理
    Vue.http.interceptors.push((request, next) => {

        // 把所有请求都以 / 结尾
        request.url = fixURL(request.url);

        // 后台返回的数据格式统一解析成json
        next((response) => {

            if (response && response.status === NO_AUTHORIZATION) {
                reLogin();
            }

            // 解决后台没有返回content-type时，responseType识别成application/xml的问题，这里添加规避处理
            if (!response.bodyText && typeof Blob !== 'undefined' && response.body instanceof Blob) {

                response.bodyText = new Promise((resolve) => {
                    let reader = new FileReader();

                    reader.readAsText(response.body);
                    reader.onload = () => {
                        resolve(reader.result);
                    };

                });
            }

            return jsonResponse(response, request);
        });
    });

}

// function getCSRF () {
//     return store.state.csrfToken || 'token';
// }

/**
 * 后台数据格式统一解析成json
 * @param {Object} response 响应内容
 * @param {Object} request  请求内容
 * @returns {Promise}       返回Promise
 */
function jsonResponse (response, request) {
    return response.json().then((jsonData) => {

        // 格式化成json成功
        logger.log('[ajax] [response==>json] success: %o. %o', response, jsonData);

        // 提供多jsonData，方便业务直接调用
        response.jsonData = jsonData;


        // 兼容 scloud 平台, scloud 平台通过 code 码来标识成功还是失败。
        if (typeof jsonData.code !== 'undefined') {
            jsonData.status = jsonData.code === SUCCESS_CODE;
        }


        // 前后台协商好，要有success才认为是真正的成功
        // 要不认为reject
        if (jsonData.success === false || jsonData.success === 0 || jsonData.success === 'false') {

            logger.warn('[ajax] [response==>json] jsonData.success: false', response, jsonData);

            // 在vue-resource内部状态中此标志作为resolve, reject标志
            // 可以看 function Http (options) {} 内部实现
            // success 为 false 时，不应该认为请求本身失败，因此注释掉下行语句
            // response.ok = false;
            if (checkReLogin(response, request.url, jsonData)) {
                reLogin();
            }
        }

        return response;

    }, (error) => {

        // 格式化json失败
        logger.warn('[ajax] [response==>json] error: %o. %o', response, error);

        // 相当于是取消了请求。
        if (!response.status) {
            return '';
        }
        let msg = response.body || response.data || _('网络异常，请检查网络后重试');
        if (response.status === NO_AUTHORIZATION) {
            msg = _('登录已超时，请重新登录');
        }

        // 提供jsonData，接口保持跟成功的一致
        response.jsonData = {
            success: false,
            msg
        };
        return response;
    });
}

/**
 * BBC 统一对发的请求URL作处理：
 * 除了static静态文件、login请求外，其它请求都自动要以 / 结尾
 * @param {String} url 待请求的 url
 * @returns {string}   转化为实际的 url
 */
function fixURL (url = '') {
    let ignoreList = [
        /static\//,
        /^login$/,
        /^cluster\-/,
        /^device\-/,
        /login\.cgi/
    ];

    for (let i = 0; i < ignoreList.length; i++) {
        let ignoreReg = ignoreList[i];
        if (ignoreReg.test(url)) {
            return url;
        }
    }

    // 给没有带参数的请求需要加上 /
    // if (url.slice(-1) !== '/' && url.indexOf('?') === -1) {
    //     url = url + '/';
    // }

    // 给带了参数的请求的 ? 前加上 /
    // url = url.replace(/(\w+)\?/, '$1\/\?');

    return url;
}

/**
 * 检测下是否无权限访问、检测token是否失效
 * @param {Object} res      response 响应
 * @param {String} url      请求的url
 * @param {Object} jsonData 响应内容
 * @returns {boolean}       是否401
 */
function checkReLogin (res, url, jsonData) {

    // http状态码为401时, 需跳转到登录页面
    if (res && !res.ok && res.status === NO_AUTHORIZATION) {
        return true;
    }

    // json中code为401时, 需跳转到登录页面
    return (jsonData && !jsonData.status &&
        (jsonData.code === NO_AUTHORIZATION || jsonData.code === ERROR_TOKEN));
}

/*
 * 跳转到登录页面
 */
export function reLogin () {

    // 删除cookie，跳到登录页
    document.cookie = 'authservice_session=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;';
    /* eslint-disable */
        setTimeout(()=>{
            window.location.reload();
            window.location.href = '/';
    },500)
}

Vue.prototype.$ajax = function (options, ...args) {
    return Vue.http(options, ...args).catch(res => {
        let {abort} = options;

        if (abort) {
            return Promise.reject('ajax aborted');
        }

        // 当请求本身出现错误(例如404)时, 构造一个符合前后端接口格式约定的json
        if (res) {
            res.jsonData = {
                success: false,
                code: res.status,
                msg: res.jsonData && res.jsonData.msg || _('网络异常，请检查网络后重试')
            };
        }


        return res;
    }).then(res => res.jsonData);
};

// 支持 this.$ajax.get(url, data)
// 支持 this.$ajax.get(url, data, options)
// 支持 this.$ajax.get(url)
// 支持 this.$ajax.get(options)
['get', 'head', 'jsonp'].forEach(method => {
    Vue.prototype.$ajax[method] = function (url, data, options = {}) {
        let params = [];
        if (data) {
            for (let key in data) {
                params.push(key + '=' + encodeURIComponent(data[key]));

                // if (data.hasOwnProperty(key)) {
                //     params.push(key + '=' + encodeURIComponent(data[key]));
                // }
            }
        }
        url += '?t=' + new Date().getTime();

        if (url.indexOf('?') === -1) {
            url += '?' + params.join('&');
        } else {
            url += '&' + params.join('&');
        }

        if (url && isString(url)) {
            Object.assign(options, {
                url,
                method
            });
        }

        return this(options);
    };
});


// 支持 this.$ajax.post(url, data)
// 支持 this.$ajax.post(url, data, options)
// 支持 this.$ajax.post(options)
['post', 'put', 'delete', 'patch'].forEach(method => {
    Vue.prototype.$ajax[method] = function (url, data, options = {}) {
        if (url && isString(url)) {
            Object.assign(options, {
                url,
                method,
                body: data,
                _timeout: OVER_TIME
            });
        }
        if (typeof options.body === 'object') {
            options.body = JSON.stringify(options.body);
        }
        return this(options);
    };
});

['form'].forEach(method => {
    Vue.prototype.$ajax[method] = function (url, data, options = {}) {
        if (url && isString(url)) {
            Object.assign(options, {
                url,
                method:'post',
                data
            });
        }
        return this(options);
    };
});

